/**
 * Copyright (c) 2012-2016, www.tinygroup.org (luo_guo@icloud.com).
 *
 *  Licensed under the GPL, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.gnu.org/licenses/gpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
/**
 *
 */
package org.tinygroup.remoteconfig.zk.client;

import org.apache.commons.lang.StringUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
import org.tinygroup.exception.BaseRuntimeException;
import org.tinygroup.logger.LogLevel;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;
import org.tinygroup.remoteconfig.config.ConfigPath;
import org.tinygroup.remoteconfig.config.ConfigValue;
import org.tinygroup.remoteconfig.config.Environment;
import org.tinygroup.remoteconfig.zk.config.RemoteConfig;
import org.tinygroup.remoteconfig.zk.utils.PathHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Administrator
 */
public class BaseManager {

    protected static final Logger LOGGER = LoggerFactory
            .getLogger(BaseManager.class);

    protected static ZooKeeper zooKeeper;

    protected static RemoteConfig config;

    static List<ACL> acls;


    public static RemoteConfig getConfig() {
        return config;
    }

    public static void setConfig(RemoteConfig config) {
        BaseManager.config = config;
    }

    public static void start() {
        LOGGER.logMessage(LogLevel.INFO, "开始客户端远程配置初始化...");
        try {
            LOGGER.logMessage(LogLevel.INFO, "创建远程链接...");
            zooKeeper = new ZooKeeper(getConfig().getUrls(), 2000, null);
            //赋予权限
            LOGGER.logMessage(LogLevel.INFO, "远程链接成功...");
            //创建项目基础节点,不用监听
            LOGGER.logMessage(LogLevel.INFO, "初始化ZK根节点");
            ZKManager.set("", new ConfigValue(IRemoteConfigZKConstant.REMOTE_ENVIRONMENT_BASE_DIR), null);
            Environment env = new Environment();
            env.setEnvironment(IRemoteConfigZKConstant.REMOTE_ENVIRONMENT_BASE_DIR);
            ZKDefaultEnvManager.set("", env);
            LOGGER.logMessage(LogLevel.INFO, "根节点创建完毕");
            LOGGER.logMessage(LogLevel.INFO, "客户端远程配置初始化完成");
            String usernamePassword = getConfig().getUsernamePassword();
            if (StringUtils.isNotBlank(usernamePassword)) {
                zooKeeper.addAuthInfo("digest", usernamePassword.getBytes());
                //写权限
                acls = new ArrayList<ACL>();
                acls.add(new ACL(ZooDefs.Perms.ALL, new Id("digest", DigestAuthenticationProvider.generateDigest(usernamePassword))));
            }
        } catch (Exception e) {
            throw new BaseRuntimeException("0TE120119001", e, getConfig().toString());
        }
    }

    public static void stop() {
        if (zooKeeper != null) {
            try {
                zooKeeper.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void delete(String key, ConfigPath configPath) {
        key = PathHelper.createPath(key, configPath);
        clearSimple(key);
    }

    private static void deleteSimple(String node) {
        try {
            Stat stat = zooKeeper.exists(node, false);
            if (stat != null) {
                zooKeeper.delete(node, stat.getVersion());
            } else {
                LOGGER.logMessage(LogLevel.DEBUG, String.format("节点[%s]不存在", node));
            }
        } catch (KeeperException e) {
            throw new BaseRuntimeException("0TE120119007", e, node);
        } catch (InterruptedException e) {
            throw new BaseRuntimeException("0TE120119008", e, node);
        }
    }

    private static void clearSimple(String node) {
        try {
            Stat stat = zooKeeper.exists(node, false);
            if (stat != null) {
                for (String subNode : zooKeeper.getChildren(node, false)) {
                    clearSimple(node.concat("/").concat(subNode));
                }
                deleteSimple(node);
            }
        } catch (KeeperException e) {
            throw new BaseRuntimeException("0TE120119009", e, node);
        } catch (InterruptedException e) {
            throw new BaseRuntimeException("0TE120119010", e, node);
        }
    }

    public static boolean exists(String key, ConfigPath configPath) {
        try {
            key = PathHelper.createPath(key, configPath);
            Stat stat = zooKeeper.exists(key, false);
            if (stat == null) {
                return false;
            } else {
                return true;
            }
        } catch (KeeperException e) {
            throw new BaseRuntimeException(e);
        } catch (InterruptedException e) {
            throw new BaseRuntimeException(e);
        }
    }

}
